import axios, { AxiosRequestConfig } from 'axios';
import { tansParams } from '@/utils/index';
import router from '@/router/index';
import { clearToken } from '../auth';

interface tokenConfig {
  value?: any;
  position?: any;
  key?: any;
  name?: string;
  age?: number;
}
export default class AxiosRequest {
  defaultConfig: object = {};

  tokenConfig: tokenConfig = {};

  queue: any = {};

  static failCodeMap: any;

  static extendErrorHooks: any;

  constructor(config = {}) {
    this.defaultConfig = {
      method: 'get',
      ...config,
    };
    this.tokenConfig = {};
    // 当前请求队列，为界面动画交互预留，暂时不用
    this.queue = {};
  }

  static handlerError(ctx: any | undefined) {
    try {
      const error = ctx.response;
      const failHandler = AxiosRequest.failCodeMap.get(error.status);
      if (failHandler) {
        error.message = failHandler.msg;
        AxiosRequest.addErrorLog(error);
        if (typeof failHandler.handler === 'function') {
          failHandler.handler(error);
        }
      }
      return Promise.reject(error);
    } catch {
      throw new Error(ctx);
    }
  }

  static addErrorLog(error: {
    message: any;
    status: any;
    request: { responseURL: any };
    config: { method: any };
  }) {
    const {
      message,
      status,
      request: { responseURL },
      config: { method },
    } = error;
    const info = {
      type: 'ajax',
      code: status,
      message,
      url: responseURL,
      method,
    };
    if (typeof AxiosRequest.extendErrorHooks === 'function') {
      AxiosRequest.extendErrorHooks(info);
    }
  }

  static use(rules: any) {
    this.failCodeMap = rules;
  }

  static addError(fn: any) {
    this.extendErrorHooks = fn;
  }

  destroy(url: string | number) {
    delete this.queue[url];
  }

  interceptors(
    instance: {
      interceptors: {
        request: {
          use: (
            arg0: (config: any) => any,
            arg1: (error: any) => Promise<never>
          ) => void;
        };
        response: {
          use: (
            arg0: (res: any) => any,
            arg1: (error: any) => Promise<never>
          ) => void;
        };
      };
    },
    url: string | number
  ) {
    // 请求拦截
    instance.interceptors.request.use(
      (config: any) => {
        this.queue[url] = true;
        const onLogin = config?.headers?.onLogin ?? false;
        // token 配置
        if (!onLogin) {
          if (this.tokenConfig.value) {
            config[this.tokenConfig.position][this.tokenConfig.key] =
              this.tokenConfig.value;
          }
        }
        // get请求映射params参数
        if (config.method === 'get' && config.params) {
          url = `${config.url}?${tansParams(config.params)}`;
          url = url.slice(0, -1);
          config.params = {};
          config.url = url;
        }

        return config;
      },
      (error: any) => Promise.reject(error)
    );
    // 响应拦截
    instance.interceptors.response.use(
      (res: any) => {
        this.destroy(url);
        if (res.data.code === 401) {
          clearToken();
          router.push({
            name: 'login',
          });
        } else if (res.data.code === 500 && !res.data.msg) {
          res.data.msg = '服务端错误';
        }
        return res;
      },
      (error: any) => {
        this.destroy(url);
        if (error.constructor.name === 'Cancel') {
          return Promise.reject(error);
        }
        if (error.toJSON().message === 'Network Error') {
          clearToken();
          router.push({
            name: 'login',
          });
        }
        return AxiosRequest.handlerError(error);
      }
    );
  }

  request(options: AxiosRequestConfig<any>) {
    const instance = axios.create();
    if (!options.url) {
      throw new Error('缺少请求地址!');
    }
    this.interceptors(instance, options.url);
    return instance.request({ ...this.defaultConfig, ...options });
  }
}
